home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / shells / tcshsrc.zoo / tcsh / sh.dol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-21  |  19.7 KB  |  918 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/sh.dol.c,v 3.2 1991/07/24 17:38:12 christos Exp $ */
  2. /*
  3.  * sh.dol.c: Variable substitutions
  4.  */
  5. /*-
  6.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "config.h"
  38. RCSID("$Id: sh.dol.c,v 3.2 1991/07/24 17:38:12 christos Exp $")
  39.  
  40. #include "sh.h"
  41.  
  42. /*
  43.  * C shell
  44.  */
  45.  
  46. /*
  47.  * These routines perform variable substitution and quoting via ' and ".
  48.  * To this point these constructs have been preserved in the divided
  49.  * input words.  Here we expand variables and turn quoting via ' and " into
  50.  * QUOTE bits on characters (which prevent further interpretation).
  51.  * If the `:q' modifier was applied during history expansion, then
  52.  * some QUOTEing may have occurred already, so we dont "trim()" here.
  53.  */
  54.  
  55. static int Dpeekc, Dpeekrd;    /* Peeks for DgetC and Dreadc */
  56. static Char *Dcp, **Dvp;    /* Input vector for Dreadc */
  57.  
  58. #define    DEOF    -1
  59.  
  60. #define    unDgetC(c)    Dpeekc = c
  61.  
  62. #define QUOTES        (_Q|_Q1|_ESC)    /* \ ' " ` */
  63.  
  64. /*
  65.  * The following variables give the information about the current
  66.  * $ expansion, recording the current word position, the remaining
  67.  * words within this expansion, the count of remaining words, and the
  68.  * information about any : modifier which is being applied.
  69.  */
  70. #define MAXWLEN (BUFSIZ - 4)
  71. #ifndef COMPAT
  72. #define MAXMOD MAXWLEN        /* This cannot overflow    */
  73. #endif /* COMPAT */
  74. static Char *dolp;        /* Remaining chars from this word */
  75. static Char **dolnxt;        /* Further words */
  76. static int dolcnt;        /* Count of further words */
  77. #ifdef COMPAT
  78. static Char dolmod;        /* : modifier character */
  79. #else
  80. static Char dolmod[MAXMOD];    /* : modifier character */
  81. static int dolnmod;        /* Number of modifiers */
  82. #endif /* COMPAT */
  83. static int dolmcnt;        /* :gx -> 10000, else 1 */
  84.  
  85. static    void     Dfix2        __P((Char **));
  86. static    Char     *Dpack        __P((Char *, Char *));
  87. static    int     Dword        __P((void));
  88. static    void     dolerror    __P((Char *));
  89. static    int     DgetC        __P((int));
  90. static    void     Dgetdol    __P((void));
  91. static    void     fixDolMod    __P((void));
  92. static    void     setDolp    __P((Char *));
  93. static    void     unDredc    __P((int));
  94. static    int     Dredc        __P((void));
  95. static    void     Dtestq        __P((int));
  96.  
  97. /*
  98.  * Fix up the $ expansions and quotations in the
  99.  * argument list to command t.
  100.  */
  101. void
  102. Dfix(t)
  103.     register struct command *t;
  104. {
  105.     register Char **pp;
  106.     register Char *p;
  107.  
  108.     if (noexec)
  109.     return;
  110.     /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
  111.     for (pp = t->t_dcom; p = *pp++;)
  112.     for (; *p; p++) {
  113.         if (cmap(*p, _DOL | QUOTES)) {    /* $, \, ', ", ` */
  114.         Dfix2(t->t_dcom);    /* found one */
  115.         blkfree(t->t_dcom);
  116.         t->t_dcom = gargv;
  117.         gargv = 0;
  118.         return;
  119.         }
  120.     }
  121. }
  122.  
  123. /*
  124.  * $ substitute one word, for i/o redirection
  125.  */
  126. Char   *
  127. Dfix1(cp)
  128.     register Char *cp;
  129. {
  130.     Char   *Dv[2];
  131.  
  132.     if (noexec)
  133.     return (0);
  134.     Dv[0] = cp;
  135.     Dv[1] = NOSTR;
  136.     Dfix2(Dv);
  137.     if (gargc != 1) {
  138.     setname(short2str(cp));
  139.     stderror(ERR_NAME | ERR_AMBIG);
  140.     }
  141.     cp = Strsave(gargv[0]);
  142.     blkfree(gargv), gargv = 0;
  143.     return (cp);
  144. }
  145.  
  146. /*
  147.  * Subroutine to do actual fixing after state initialization.
  148.  */
  149. static void
  150. Dfix2(v)
  151.     Char  **v;
  152. {
  153.     ginit();            /* Initialize glob's area pointers */
  154.     Dvp = v;
  155.     Dcp = STRNULL;        /* Setup input vector for Dreadc */
  156.     unDgetC(0);
  157.     unDredc(0);            /* Clear out any old peeks (at error) */
  158.     dolp = 0;
  159.     dolcnt = 0;            /* Clear out residual $ expands (...) */
  160.     while (Dword())
  161.     continue;
  162. }
  163.  
  164. /*
  165.  * Pack up more characters in this word
  166.  */
  167. static Char *
  168. Dpack(wbuf, wp)
  169.     Char   *wbuf, *wp;
  170. {
  171.     register int c;
  172.     register int i = MAXWLEN - (wp - wbuf);
  173.  
  174.     for (;;) {
  175.     c = DgetC(DODOL);
  176.     if (c == escchar) {
  177.         c = DgetC(0);
  178.         if (c == DEOF) {
  179.         unDredc(c);
  180.         *wp = 0;
  181.         Gcat(STRNULL, wbuf);
  182.         return (NULL);
  183.         }
  184.         if (c == '\n')
  185.         c = ' ';
  186.         else
  187.         c |= QUOTE;
  188.     }
  189.     if (c == DEOF) {
  190.         unDredc(c);
  191.         *wp = 0;
  192.         Gcat(STRNULL, wbuf);
  193.         return (NULL);
  194.     }
  195.     if (cmap(c, _SP | _NL | _Q | _Q1)) {    /* sp \t\n'"` */
  196.         unDgetC(c);
  197.         if (cmap(c, QUOTES))
  198.         return (wp);
  199.         *wp++ = 0;
  200.         Gcat(STRNULL, wbuf);
  201.         return (NULL);
  202.     }
  203.     if (--i <= 0)
  204.         stderror(ERR_WTOOLONG);
  205.     *wp++ = c;
  206.     }
  207. }
  208.  
  209. /*
  210.  * Get a word.  This routine is analogous to the routine
  211.  * word() in sh.lex.c for the main lexical input.  One difference
  212.  * here is that we don't get a newline to terminate our expansion.
  213.  * Rather, DgetC will return a DEOF when we hit the end-of-input.
  214.  */
  215. static int
  216. Dword()
  217. {
  218.     register int c, c1;
  219.     Char    wbuf[BUFSIZ];
  220.     register Char *wp = wbuf;
  221.     register int i = MAXWLEN;
  222.     register bool dolflg;
  223.     bool    sofar = 0, done = 0;
  224.  
  225.     while (!done) {
  226.     done = 1;
  227.     c = DgetC(DODOL);
  228.     switch (c) {
  229.  
  230.     case DEOF:
  231.         if (sofar == 0)
  232.         return (0);
  233.         /* finish this word and catch the code above the next time */
  234.         unDredc(c);
  235.         /* fall into ... */
  236.  
  237.     case '\n':
  238.         *wp = 0;
  239.         Gcat(STRNULL, wbuf);
  240.         return (1);
  241.  
  242.     case ' ':
  243.     case '\t':
  244.         done = 0;
  245.         break;
  246.  
  247.     case '`':
  248.         /* We preserve ` quotations which are done yet later */
  249.         *wp++ = c, --i;
  250.     case '\'':
  251.     case '"':
  252.         /*
  253.          * Note that DgetC never returns a QUOTES character from an
  254.          * expansion, so only true input quotes will get us here or out.
  255.          */
  256.         c1 = c;
  257.         dolflg = c1 == '"' ? DODOL : 0;
  258.         for (;;) {
  259.         c = DgetC(dolflg);
  260.         if (c == c1)
  261.             break;
  262.         if (c == '\n' || c == DEOF)
  263.             stderror(ERR_UNMATCHED, c1);
  264.         if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE))
  265.             --wp, ++i;
  266.         if (--i <= 0)
  267.             stderror(ERR_WTOOLONG);
  268.         switch (c1) {
  269.  
  270.         case '"':
  271.             /*
  272.              * Leave any `s alone for later. Other chars are all
  273.              * quoted, thus `...` can tell it was within "...".
  274.              */
  275.             *wp++ = c == '`' ? '`' : c | QUOTE;
  276.             break;
  277.  
  278.         case '\'':
  279.             /* Prevent all further interpretation */
  280.             *wp++ = c | QUOTE;
  281.             break;
  282.  
  283.         case '`':
  284.             /* Leave all text alone for later */
  285.             *wp++ = c;
  286.             break;
  287.         }
  288.         }
  289.         if (c1 == '`')
  290.         *wp++ = '`' /* i--; eliminated */;
  291.         sofar = 1;
  292.         if ((wp = Dpack(wbuf, wp)) == NULL)
  293.         return (1);
  294.         else {
  295.         i = MAXWLEN - (wp - wbuf);
  296.         done = 0;
  297.         }
  298.         break;
  299.  
  300. #ifdef ALTESC
  301.     default:
  302.         if (c != escchar) break;
  303. #else
  304.     case '\\':
  305. #endif
  306.         c = DgetC(0);    /* No $ subst! */
  307.         if (c == '\n' || c == DEOF) {
  308.         done = 0;
  309.         break;
  310.         }
  311.         c |= QUOTE;
  312.         break;
  313.     }
  314.     if (done) {
  315.         unDgetC(c);
  316.         sofar = 1;
  317.         if ((wp = Dpack(wbuf, wp)) == NULL)
  318.         return (1);
  319.         else {
  320.         i = MAXWLEN - (wp - wbuf);
  321.         done = 0;
  322.         }
  323.     }
  324.     }
  325.     /* Really NOTREACHED */
  326.     return (0);
  327. }
  328.  
  329.  
  330. /*
  331.  * Get a character, performing $ substitution unless flag is 0.
  332.  * Any QUOTES character which is returned from a $ expansion is
  333.  * QUOTEd so that it will not be recognized above.
  334.  */
  335. static int
  336. DgetC(flag)
  337.     register int flag;
  338. {
  339.     register int c;
  340.  
  341. top:
  342.     if (c = Dpeekc) {
  343.     Dpeekc = 0;
  344.     return (c);
  345.     }
  346.     if (lap) {
  347.     c = *lap++ & (QUOTE | TRIM);
  348.     if (c == 0) {
  349.         lap = 0;
  350.         goto top;
  351.     }
  352. quotspec:
  353.     if (cmap(c, QUOTES))
  354.         return (c | QUOTE);
  355.     return (c);
  356.     }
  357.     if (dolp) {
  358.     if (c = *dolp++ & (QUOTE | TRIM))
  359.         goto quotspec;
  360.     if (dolcnt > 0) {
  361.         setDolp(*dolnxt++);
  362.         --dolcnt;
  363.         return (' ');
  364.     }
  365.     dolp = 0;
  366.     }
  367.     if (dolcnt > 0) {
  368.     setDolp(*dolnxt++);
  369.     --dolcnt;
  370.     goto top;
  371.     }
  372.     c = Dredc();
  373.     if (c == '$' && flag) {
  374.     Dgetdol();
  375.     goto top;
  376.     }
  377.     return (c);
  378. }
  379.  
  380. static Char *nulvec[] = {0};
  381. static struct varent nulargv = {nulvec, STRargv, 0};
  382.  
  383. static void
  384. dolerror(s)
  385.     Char   *s;
  386. {
  387.     setname(short2str(s));
  388.     stderror(ERR_NAME | ERR_RANGE);
  389. }
  390.  
  391. /*
  392.  * Handle the multitudinous $ expansion forms.
  393.  * Ugh.
  394.  */
  395. static void
  396. Dgetdol()
  397. {
  398.     register Char *np;
  399.     register struct varent *vp = NULL;
  400.     Char    name[4 * MAXVARLEN + 1];
  401.     int     c, sc;
  402.     int     subscr = 0, lwb = 1, upb = 0;
  403.     bool    dimen = 0, bitset = 0;
  404.     char    tnp;
  405.     Char    wbuf[BUFSIZ];
  406.  
  407. #ifdef COMPAT
  408.     dolmod = dolmcnt = 0;
  409. #else
  410.     dolnmod = dolmcnt = 0;
  411. #endif /* COMPAT */
  412.     c = sc = DgetC(0);
  413.     if (c == '{')
  414.     c = DgetC(0);        /* sc is { to take } later */
  415.     if ((c & TRIM) == '#')
  416.     dimen++, c = DgetC(0);    /* $# takes dimension */
  417.     else if (c == '?')
  418.     bitset++, c = DgetC(0);    /* $? tests existence */
  419.     switch (c) {
  420.  
  421.     case '$':
  422.     if (dimen || bitset)
  423.         stderror(ERR_SYNTAX);
  424.     setDolp(doldol);
  425.     goto eatbrac;
  426.  
  427.     case '<' | QUOTE:
  428.     if (bitset)
  429.         stderror(ERR_NOTALLOWED, "$?<");
  430.     if (dimen)
  431.         stderror(ERR_NOTALLOWED, "$?#");
  432.     for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) {
  433. #ifdef __MINT__
  434.     /* strip out carriage returns */
  435.         while (tnp == '\r') {
  436.         if (read(OLDSTD, &tnp, 1) != 1) break;
  437.         }
  438. #endif
  439.         *np = tnp;
  440.         if (np >= &wbuf[BUFSIZ - 1])
  441.         stderror(ERR_LTOOLONG);
  442.         if (SIGN_EXTEND_CHAR(tnp) <= 0 || tnp == '\n')
  443.         break;
  444.     }
  445.     *np = 0;
  446.     /*
  447.      * KLUDGE: dolmod is set here because it will cause setDolp to call
  448.      * domod and thus to copy wbuf. Otherwise setDolp would use it
  449.      * directly. If we saved it ourselves, no one would know when to free
  450.      * it. The actual function of the 'q' causes filename expansion not to
  451.      * be done on the interpolated value.
  452.      */
  453. #ifdef COMPAT
  454.     dolmod = 'q';
  455. #else
  456.     dolmod[dolnmod++] = 'q';
  457. #endif /* COMPAT */
  458.     dolmcnt = 10000;
  459.     setDolp(wbuf);
  460.     goto eatbrac;
  461.  
  462.     case DEOF:
  463.     case '\n':
  464.     stderror(ERR_SYNTAX);
  465.     /* NOTREACHED */
  466.     break;
  467.  
  468.     case '*':
  469.     (void) Strcpy(name, STRargv);
  470.     vp = adrof(STRargv);
  471.     subscr = -1;        /* Prevent eating [...] */
  472.     break;
  473.  
  474.     default:
  475.     np = name;
  476.     if (Isdigit(c)) {
  477.         if (dimen)
  478.         stderror(ERR_NOTALLOWED, "$#<num>");
  479.         subscr = 0;
  480.         do {
  481.         subscr = subscr * 10 + c - '0';
  482.         c = DgetC(0);
  483.         } while (Isdigit(c));
  484.         unDredc(c);
  485.         if (subscr < 0) {
  486.         dolerror(vp->v_name);
  487.         return;
  488.         }
  489.         if (subscr == 0) {
  490.         if (bitset) {
  491.             dolp = ffile ? STR1 : STR0;
  492.             goto eatbrac;
  493.         }
  494.         if (ffile == 0)
  495.             stderror(ERR_DOLZERO);
  496.         fixDolMod();
  497.         setDolp(ffile);
  498.         goto eatbrac;
  499.         }
  500.         if (bitset)
  501.         stderror(ERR_DOLQUEST);
  502.         vp = adrof(STRargv);
  503.         if (vp == 0) {
  504.         vp = &nulargv;
  505.         goto eatmod;
  506.         }
  507.         break;
  508.     }
  509.     if (!alnum(c))
  510.         stderror(ERR_VARALNUM);
  511.     for (;;) {
  512.         *np++ = c;
  513.         c = DgetC(0);
  514.         if (!alnum(c))
  515.         break;
  516.         if (np >= &name[MAXVARLEN])
  517.         stderror(ERR_VARTOOLONG);
  518.     }
  519.     *np++ = 0;
  520.     unDredc(c);
  521.     vp = adrof(name);
  522.     }
  523.     if (bitset) {
  524.     dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
  525.     goto eatbrac;
  526.     }
  527.     if (vp == 0) {
  528.     np = str2short(getenv(short2str(name)));
  529.     if (np) {
  530.         fixDolMod();
  531.         setDolp(np);
  532.         goto eatbrac;
  533.     }
  534.     udvar(name);
  535.     /* NOTREACHED */
  536.     }
  537.     c = DgetC(0);
  538.     upb = blklen(vp->vec);
  539.     if (dimen == 0 && subscr == 0 && c == '[') {
  540.     np = name;
  541.     for (;;) {
  542.         c = DgetC(DODOL);    /* Allow $ expand within [ ] */
  543.         if (c == ']')
  544.         break;
  545.         if (c == '\n' || c == DEOF)
  546.         stderror(ERR_INCBR);
  547.         if (np >= &name[sizeof(name) / sizeof(Char) - 2])
  548.         stderror(ERR_VARTOOLONG);
  549.         *np++ = c;
  550.     }
  551.     *np = 0, np = name;
  552.     if (dolp || dolcnt)    /* $ exp must end before ] */
  553.         stderror(ERR_EXPORD);
  554.     if (!*np)
  555.         stderror(ERR_SYNTAX);
  556.     if (Isdigit(*np)) {
  557.         int     i;
  558.  
  559.         for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0');
  560.         if ((i < 0 || i > upb) && !any("-*", *np)) {
  561.         dolerror(vp->v_name);
  562.         return;
  563.         }
  564.         lwb = i;
  565.         if (!*np)
  566.         upb = lwb, np = STRstar;
  567.     }
  568.     if (*np == '*')
  569.         np++;
  570.     else if (*np != '-')
  571.         stderror(ERR_MISSING, '-');
  572.     else {
  573.         register int i = upb;
  574.  
  575.         np++;
  576.         if (Isdigit(*np)) {
  577.         i = 0;
  578.         while (Isdigit(*np))
  579.             i = i * 10 + *np++ - '0';
  580.         if (i < 0 || i > upb) {
  581.             dolerror(vp->v_name);
  582.             return;
  583.         }
  584.         }
  585.         if (i < lwb)
  586.         upb = lwb - 1;
  587.         else
  588.         upb = i;
  589.     }
  590.     if (lwb == 0) {
  591.         if (upb != 0) {
  592.         dolerror(vp->v_name);
  593.         return;
  594.         }
  595.         upb = -1;
  596.     }
  597.     if (*np)
  598.         stderror(ERR_SYNTAX);
  599.     }
  600.     else {
  601.     if (subscr > 0)
  602.         if (subscr > upb)
  603.         lwb = 1, upb = 0;
  604.         else
  605.         lwb = upb = subscr;
  606.     unDredc(c);
  607.     }
  608.     if (dimen) {
  609.     Char   *cp = putn(upb - lwb + 1);
  610.  
  611.     addla(cp);
  612.     xfree((ptr_t) cp);
  613.     }
  614.     else {
  615. eatmod:
  616.     fixDolMod();
  617.     dolnxt = &vp->vec[lwb - 1];
  618.     dolcnt = upb - lwb + 1;
  619.     }
  620. eatbrac:
  621.     if (sc == '{') {
  622.     c = Dredc();
  623.     if (c != '}')
  624.         stderror(ERR_MISSING, '}');
  625.     }
  626. }
  627.  
  628. static void
  629. fixDolMod()
  630. {
  631.     register int c;
  632.  
  633.     c = DgetC(0);
  634.     if (c == ':') {
  635. #ifndef COMPAT
  636.     do {
  637. #endif /* COMPAT */
  638.         c = DgetC(0), dolmcnt = 1;
  639.         if (c == 'g')
  640.         c = DgetC(0), dolmcnt = 10000;
  641.         if (!any("htrqxe", c))
  642.         stderror(ERR_BADMOD, c);
  643. #ifndef COMPAT
  644.         dolmod[dolnmod++] = c;
  645. #else
  646.         dolmod = c;
  647. #endif /* COMPAT */
  648.         if (c == 'q')
  649.         dolmcnt = 10000;
  650. #ifndef COMPAT
  651.     }
  652.     while ((c = DgetC(0)) == ':');
  653.     unDredc(c);
  654. #endif /* COMPAT */
  655.     }
  656.     else
  657.     unDredc(c);
  658. }
  659.  
  660. static void
  661. setDolp(cp)
  662.     register Char *cp;
  663. {
  664.     register Char *dp;
  665. #ifndef COMPAT
  666.     int i;
  667. #endif /* COMPAT */
  668.  
  669. #ifdef COMPAT
  670.     if (dolmod == 0 || dolmcnt == 0) {
  671. #else
  672.     if (dolnmod == 0 || dolmcnt == 0) {
  673. #endif /* COMPAT */
  674.     dolp = cp;
  675.     return;
  676.     }
  677. #ifdef COMPAT
  678.     dp = domod(cp, dolmod);
  679. #else
  680.     dp = cp = Strsave(cp);
  681.     for (i = 0; i < dolnmod; i++)
  682.     if ((dp = domod(cp, dolmod[i]))) {
  683.         xfree((ptr_t) cp);
  684.         cp = dp;
  685.         dolmcnt--;
  686.     }
  687.     else {
  688.         dp = cp;
  689.         break;
  690.     }
  691. #endif /* COMPAT */
  692.  
  693.     if (dp) {
  694. #ifdef COMPAT
  695.     dolmcnt--;
  696. #endif /* COMPAT */
  697.     addla(dp);
  698.     xfree((ptr_t) dp);
  699.     }
  700. #ifndef COMPAT
  701.     else
  702.     addla(cp);
  703. #endif /* COMPAT */
  704.  
  705.     dolp = STRNULL;
  706.     if (seterr)
  707.     stderror(ERR_OLD);
  708. }
  709.  
  710. static void
  711. unDredc(c)
  712.     int     c;
  713. {
  714.  
  715.     Dpeekrd = c;
  716. }
  717.  
  718. static int
  719. Dredc()
  720. {
  721.     register int c;
  722.  
  723.     if (c = Dpeekrd) {
  724.     Dpeekrd = 0;
  725.     return (c);
  726.     }
  727.     if (Dcp && (c = *Dcp++))
  728.     return (c & (QUOTE | TRIM));
  729.     if (*Dvp == 0) {
  730.     Dcp = 0;
  731.     return (DEOF);
  732.     }
  733.     Dcp = *Dvp++;
  734.     return (' ');
  735. }
  736.  
  737. static void
  738. Dtestq(c)
  739.     register int c;
  740. {
  741.  
  742.     if (cmap(c, QUOTES))
  743.     gflag = 1;
  744. }
  745.  
  746. /*
  747.  * Form a shell temporary file (in unit 0) from the words
  748.  * of the shell input up to EOF or a line the same as "term".
  749.  * Unit 0 should have been closed before this call.
  750.  */
  751. void
  752. heredoc(term)
  753.     Char   *term;
  754. {
  755.     register int c;
  756.     Char   *Dv[2];
  757.     Char    obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
  758.     int     ocnt, lcnt, mcnt;
  759.     register Char *lbp, *obp, *mbp;
  760.     Char  **vp;
  761.     bool    quoted;
  762. #ifdef __MINT__
  763.     int tf;
  764.     extern int csh_tmpfile();    /* in sh.c */
  765.  
  766.     tf = csh_tmpfile();
  767.     if (tf < 0)
  768.         stderror(ERR_SYSTEM, "tmpfile", strerror(errno));
  769.     (void)dup2(tf, 0);
  770.     (void)close(tf);
  771. #else
  772.     char   *tmp;
  773.     if (creat(tmp = short2str(shtemp), 0600) < 0)
  774.     stderror(ERR_SYSTEM, tmp, strerror(errno));
  775.     (void) close(0);
  776.     if (open(tmp, O_RDWR) < 0) {
  777.     int     oerrno = errno;
  778.  
  779.     (void) unlink(tmp);
  780.     errno = oerrno;
  781.     stderror(ERR_SYSTEM, tmp, strerror(errno));
  782.     }
  783.  
  784.     (void) unlink(tmp);        /* 0 0 inode! */
  785. #endif /* __MINT__ */
  786.  
  787.     Dv[0] = term;
  788.     Dv[1] = NOSTR;
  789.     gflag = 0;
  790.     trim(Dv);
  791.     rscan(Dv, Dtestq);
  792.     quoted = gflag;
  793.     ocnt = BUFSIZ;
  794.     obp = obuf;
  795.     for (;;) {
  796.     /*
  797.      * Read up a line
  798.      */
  799.     lbp = lbuf;
  800.     lcnt = BUFSIZ - 4;
  801.     for (;;) {
  802.         c = readc(1);    /* 1 -> Want EOF returns */
  803.         if (c < 0 || c == '\n')
  804.         break;
  805.         if (c &= TRIM) {
  806.         *lbp++ = c;
  807.         if (--lcnt < 0) {
  808.             setname("<<");
  809.             stderror(ERR_NAME | ERR_OVERFLOW);
  810.         }
  811.         }
  812.     }
  813.     *lbp = 0;
  814.  
  815.     /*
  816.      * Check for EOF or compare to terminator -- before expansion
  817.      */
  818.     if (c < 0 || eq(lbuf, term)) {
  819.         (void) write(0, short2str(obuf), (size_t) (BUFSIZ - ocnt));
  820.         (void) lseek(0, 0l, L_SET);
  821.         return;
  822.     }
  823.  
  824.     /*
  825.      * If term was quoted or -n just pass it on
  826.      */
  827.     if (quoted || noexec) {
  828.         *lbp++ = '\n';
  829.         *lbp = 0;
  830.         for (lbp = lbuf; c = *lbp++;) {
  831.         *obp++ = c;
  832.         if (--ocnt == 0) {
  833.             (void) write(0, short2str(obuf), BUFSIZ);
  834.             obp = obuf;
  835.             ocnt = BUFSIZ;
  836.         }
  837.         }
  838.         continue;
  839.     }
  840.  
  841.     /*
  842.      * Term wasn't quoted so variable and then command expand the input
  843.      * line
  844.      */
  845.     Dcp = lbuf;
  846.     Dvp = Dv + 1;
  847.     mbp = mbuf;
  848.     mcnt = BUFSIZ - 4;
  849.     for (;;) {
  850.         c = DgetC(DODOL);
  851.         if (c == DEOF)
  852.         break;
  853.         if ((c &= TRIM) == 0)
  854.         continue;
  855.         /* \ quotes \ $ ` here */
  856.         if (c == escchar) {
  857.         c = DgetC(0);
  858. #ifdef ALTESC
  859.         if (c != '$' && c != escchar && c != '`')
  860. #else
  861.         if (!any("$\\`", c))
  862. #endif
  863.             unDgetC(c | QUOTE), c = escchar;
  864.         else
  865.             c |= QUOTE;
  866.         }
  867.         *mbp++ = c;
  868.         if (--mcnt == 0) {
  869.         setname("<<");
  870.         stderror(ERR_NAME | ERR_OVERFLOW);
  871.         }
  872.     }
  873.     *mbp++ = 0;
  874.  
  875.     /*
  876.      * If any ` in line do command substitution
  877.      */
  878.     mbp = mbuf;
  879.     if (any(short2str(mbp), '`')) {
  880.         /*
  881.          * 1 arg to dobackp causes substitution to be literal. Words are
  882.          * broken only at newlines so that all blanks and tabs are
  883.          * preserved.  Blank lines (null words) are not discarded.
  884.          */
  885.         vp = dobackp(mbuf, 1);
  886.     }
  887.     else
  888.         /* Setup trivial vector similar to return of dobackp */
  889.         Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv;
  890.  
  891.     /*
  892.      * Resurrect the words from the command substitution each separated by
  893.      * a newline.  Note that the last newline of a command substitution
  894.      * will have been discarded, but we put a newline after the last word
  895.      * because this represents the newline after the last input line!
  896.      */
  897.     for (; *vp; vp++) {
  898.         for (mbp = *vp; *mbp; mbp++) {
  899.         *obp++ = *mbp & TRIM;
  900.         if (--ocnt == 0) {
  901.             (void) write(0, short2str(obuf), BUFSIZ);
  902.             obp = obuf;
  903.             ocnt = BUFSIZ;
  904.         }
  905.         }
  906.         *obp++ = '\n';
  907.         if (--ocnt == 0) {
  908.         (void) write(0, short2str(obuf), BUFSIZ);
  909.         obp = obuf;
  910.         ocnt = BUFSIZ;
  911.         }
  912.     }
  913.     if (pargv)
  914.         blkfree(pargv), pargv = 0;
  915.     }
  916. }
  917.  
  918.